﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BCCommon;
using BCData.TMS.MallInterface.MallOrder;
using BCData.TMS.MallInterface.MallOrderAddress;
using BCData.TMS.MallInterface.MallOrderGoods;
using BCDto.TMS.MallInterface;
using BCEntity.TMS.MallInterface.MallOrder;
using BCEntity.TMS.MallInterface.MallOrderAddress;
using BCCommon.TMS.MallInterface;
using BCEntity.TMS.MallInterface.MallOrderGoods;
using BCService.Utils;
using BCDto.TMS.TransportOrder;
using BCDto.TMS.Order.Order;
using BCCommon.TMS.Order;
using BCCommon.TMS.FreightEnums;
using KafkaNet.Protocol;
using BCService.TMS.Agent.AgentBranchesConfig;
using BCCommon.TMS.Transport;
using BCService.TMS.TransportOrder;
using BCService.TMS.VehicleTypeService;
using Microsoft.Extensions.Configuration;

namespace BCService.TMS.MallInterface.MallOrder
{
    public class MallOrderService : IMallOrderService
    {
        private readonly IRedisService redisService;
        private readonly IDatabaseContext databaseContext;
        private readonly IMallOrderData mallOrderData;
        private readonly IMallOrderAddressData mallOrderAddressData;
        private readonly IMallOrderGoodsData mallOrderGoodsData;
        private readonly IAgentBranchesConfigService agentBranchesConfigService;
        private readonly ITransportOrderService transportOrderService;
        private readonly IVehicleTypeService vehicleTypeService;
        private readonly IConfiguration configuration;

        public MallOrderService(IRedisService redisService, IDatabaseContext databaseContext, IMallOrderData mallOrderData, IMallOrderAddressData mallOrderAddressData, IMallOrderGoodsData mallOrderGoodsData, IAgentBranchesConfigService agentBranchesConfigService, ITransportOrderService transportOrderService, IConfiguration configuration)
        {
            this.redisService = redisService;
            this.databaseContext = databaseContext;
            this.mallOrderData = mallOrderData;
            this.mallOrderAddressData = mallOrderAddressData;
            this.mallOrderGoodsData = mallOrderGoodsData;
            this.agentBranchesConfigService = agentBranchesConfigService;
            this.transportOrderService = transportOrderService;
            this.configuration = configuration;
        }

        #region 添加
        public void Add(MallOrderDto mallOrderDto)
        {
            var mallOrderEntity = mallOrderData.GetEntityAsync(mallOrderDto.MallOrderNo).GetAwaiter().GetResult();
            databaseContext.BeginTransaction();
            if (mallOrderEntity != null)
            {
                mallOrderData.DeleteAsync(mallOrderEntity.MallOrderId).GetAwaiter().GetResult();
                mallOrderAddressData.DeleteAsync(mallOrderEntity.MallOrderNo).GetAwaiter().GetResult();
                mallOrderGoodsData.DeleteAsync(mallOrderEntity.MallOrderNo).GetAwaiter().GetResult();
            }

            mallOrderData.InsertAsync(GetMallOrderEntity(mallOrderDto)).GetAwaiter().GetResult();
            mallOrderAddressData.InsertAsync(GetMallOrderAddressEntity(mallOrderDto, MallOrderSRType.SENDER)).GetAwaiter().GetResult();
            mallOrderAddressData.InsertAsync(GetMallOrderAddressEntity(mallOrderDto, MallOrderSRType.RECEIVER)).GetAwaiter().GetResult();
            var list = GetMallOrderGoodsEntityList(mallOrderDto);
            foreach (var item in list)
            {
                mallOrderGoodsData.InsertAsync(item).GetAwaiter().GetResult();
            }
            databaseContext.Commit();
        }

        private MallOrderEntity GetMallOrderEntity(MallOrderDto mallOrderDto)
        {

            MallOrderEntity entity = new MallOrderEntity();
            entity.MallOrderNo = mallOrderDto.MallOrderNo;
            entity.MallShopNo = mallOrderDto.MallShopNo;
            entity.CreateTime = DateTime.Now;
            entity.PayType = mallOrderDto.PayType;
            entity.IsInsuredPrice = mallOrderDto.IsInsuredPrice;
            entity.InsuredPrice = mallOrderDto.InsuredPrice;
            entity.IsReturnSignBill = mallOrderDto.IsReturnSignBill;
            if (!string.IsNullOrWhiteSpace(mallOrderDto.StartDate))
            {
                if (DateTime.TryParse(mallOrderDto.StartDate, out DateTime start))
                {
                    entity.StartDate = start;

                    if (!string.IsNullOrWhiteSpace(mallOrderDto.EndDate))
                    {
                        if (DateTime.TryParse(mallOrderDto.EndDate, out DateTime end))
                        {
                            entity.EndDate = end;
                        }
                    }
                }
            }
            entity.Remark = mallOrderDto.Remark;
            return entity;
        }

        private MallOrderAddressEntity GetMallOrderAddressEntity(MallOrderDto mallOrderDto, MallOrderSRType orderSRType)
        {
            MallOrderAddressDto addressDto = null;

            if (orderSRType == MallOrderSRType.SENDER)
                addressDto = mallOrderDto.Sender;
            else
                addressDto = mallOrderDto.Receiver;


            MallOrderAddressEntity entity = new MallOrderAddressEntity();
            entity.MallOrderNo = mallOrderDto.MallOrderNo;
            entity.SRType = orderSRType.ToString();
            entity.MallShopNo = addressDto.MallShopNo;
            entity.MallShopName = addressDto.MallShopName;
            entity.CompanyName = addressDto.CompanyName;
            entity.ContactName = addressDto.ContantName;
            entity.Tel = addressDto.Tel;
            entity.Mobile = addressDto.Mobile;
            entity.ProvinceCode = addressDto.ProvinceCode;
            entity.ProvinceName = addressDto.ProvinceName;
            entity.CityCode = addressDto.CityCode;
            entity.CityName = addressDto.CityName;
            entity.CountyCode = addressDto.CountyCode;
            entity.CountyName = addressDto.CountyName;
            entity.Address = addressDto.Address;
            entity.Lng = addressDto.Lng;
            entity.Lat = addressDto.Lat;

            return entity;
        }

        private List<MallOrderGoodsEntity> GetMallOrderGoodsEntityList(MallOrderDto mallOrderDto)
        {
            List<MallOrderGoodsEntity> list = mallOrderDto.MallGoodsList.As<List<MallOrderGoodsEntity>>();
            list.ForEach(s => s.MallOrderNo = mallOrderDto.MallOrderNo);
            return list;
        }

        #endregion

        #region 修改订单拆分状态
        public MallOrderEntity UpdateOrderSpilt(string mallOrderNo, long agentBranchesConfigId)
        {
            var entity = mallOrderData.GetEntityAsync(mallOrderNo).GetAwaiter().GetResult() ?? throw new Exception("找不到商城订单信息!");
            entity.IsNeedSplit = true;
            entity.AgentBranchesConfigId = agentBranchesConfigId;
            return mallOrderData.UpdateAsync(entity).GetAwaiter().GetResult();
        }
        #endregion

        #region 修改订单运输业务类型
        public MallOrderEntity UpdateOrderTransportBusinessType(string mallOrderNo, TransportBusinessType transportBusinessType)
        {
            var entity = mallOrderData.GetEntityAsync(mallOrderNo).GetAwaiter().GetResult() ?? throw new Exception("找不到商城订单信息!");
            entity.TransportBusinessType = transportBusinessType.ToString();
            return mallOrderData.UpdateAsync(entity).GetAwaiter().GetResult();
        }
        #endregion

        #region 修改订单运输订单编号
        public MallOrderEntity UpdateOrderTransportOrderNo(string mallOrderNo, string transportOrderNo)
        {
            var entity = mallOrderData.GetEntityAsync(mallOrderNo).GetAwaiter().GetResult() ?? throw new Exception("找不到商城订单信息!");
            entity.TransportOrderNo = transportOrderNo;
            return mallOrderData.UpdateAsync(entity).GetAwaiter().GetResult();
        }
        #endregion

        #region 修改订单运费
        public MallOrderEntity UpdateOrderTransportCost(string mallOrderNo, string transportCost)
        {
            var entity = mallOrderData.GetEntityAsync(mallOrderNo).GetAwaiter().GetResult() ?? throw new Exception("找不到商城订单信息!");
            entity.TransportCost = transportCost;
            return mallOrderData.UpdateAsync(entity).GetAwaiter().GetResult();
        }
        #endregion



        #region 创建订单
        public void CreateOrder(MallOrderConfirmDto mallOrderConfirmDto)
        {
            OrderBaseRequestDto baseRequest = null;

            var mallOrderEntity = mallOrderData.GetEntityAsync(mallOrderConfirmDto.MallOrderNo).GetAwaiter().GetResult() ?? throw new Exception("找不到运费计算后的订单信息!");
            var addressList = mallOrderAddressData.GetAddressListAsync(mallOrderConfirmDto.MallOrderNo).GetAwaiter().GetResult() ?? throw new Exception("找不到运费计算后的订单地址信息!");
            if (addressList.Count() < 2) throw new Exception("运费计算后的订单地址信息不完整!");
            var goodsList = mallOrderGoodsData.GetGoodsListAsync(mallOrderConfirmDto.MallOrderNo).GetAwaiter().GetResult() ?? throw new Exception("找不到运费计算后的订单货物信息!");

            var sender = addressList.FirstOrDefault(s => s.SRType == MallOrderSRType.SENDER.ToString());
            var receiver = addressList.FirstOrDefault(s => s.SRType == MallOrderSRType.RECEIVER.ToString());

            //你这里需要创建运输订单id，然后传入orderService.Create的第三个参数。
            var transportOrderDto = CreateTransportOrder(mallOrderEntity, sender, receiver);
            UpdateOrderTransportOrderNo(mallOrderConfirmDto.MallOrderNo, transportOrderDto.TransportOrderNo);

            if (mallOrderEntity.IsNeedSplit)
            {
                if (mallOrderEntity.AgentBranchesConfigId.HasValue)
                {
                    //拆单
                    MallOrderAddressEntity transStationAddress = new MallOrderAddressEntity();

                    var agentBranches = agentBranchesConfigService.GetById(mallOrderEntity.AgentBranchesConfigId.Value) ?? throw new Exception("找不到运费计算后的中转站信息!");
                    transStationAddress.Address = agentBranches.Address;
                    if (!agentBranches.Latitude.HasValue || !agentBranches.Longitude.HasValue) throw new Exception("中转站配置没有经度纬度信息!");
                    transStationAddress.Lng = agentBranches.Longitude.Value;
                    transStationAddress.Lat = agentBranches.Latitude.Value;
                    transStationAddress.ContactName = "XXX";//XXXXX中转点需要配置联系方式
                    transStationAddress.Mobile = "XXX";//XXXXX 

                    baseRequest = CreateOrderBaseRequestDto(mallOrderEntity, sender, transStationAddress, goodsList.ToList(), TransportBusinessType.RunErrands);
                    var orderService = transportOrderService.GetOrderService(TransportBusinessType.RunErrands, null);
                    orderService.Create(baseRequest, 0, transportOrderDto.TransportOrderId);

                    mallOrderEntity.StartDate = null;
                    baseRequest = CreateOrderBaseRequestDto(mallOrderEntity, transStationAddress, receiver, goodsList.ToList(), TransportBusinessType.SmallPieces);

                    orderService = transportOrderService.GetOrderService(TransportBusinessType.SmallPieces, null);
                    orderService.Create(baseRequest, 0, transportOrderDto.TransportOrderId);
                }
                else
                {
                    throw new Exception("找不到运费计算后的中转站配置信息");
                }
            }
            else
            {
                if (!string.IsNullOrWhiteSpace(mallOrderEntity.TransportBusinessType))
                {
                    TransportBusinessType transportBusinessType = (TransportBusinessType)Enum.Parse(typeof(TransportBusinessType), mallOrderEntity.TransportBusinessType);
                    baseRequest = CreateOrderBaseRequestDto(mallOrderEntity, sender, receiver, goodsList.ToList(), transportBusinessType);

                    var orderService = transportOrderService.GetOrderService(transportBusinessType, null);

                    orderService.Create(baseRequest, 0, transportOrderDto.TransportOrderId);
                }
                else
                {
                    throw new Exception("找不到运费计算后的运输业务类型信息!");
                }
            }
        }

        private OrderBaseRequestDto CreateOrderBaseRequestDto(MallOrderEntity mallOrderEntity, MallOrderAddressEntity sender, MallOrderAddressEntity receiver, List<MallOrderGoodsEntity> goodsList, TransportBusinessType transportBusinessType)
        {
            OrderBaseRequestDto baseRequest = null;
            if (transportBusinessType == TransportBusinessType.RunErrands)
            {
                baseRequest = new RunErrandsOrderRequestDto();
                baseRequest.VehicleTypeId = GetRunErrandVehicleTypeId();
            }
            else if (transportBusinessType == TransportBusinessType.SmallPieces)
            {
                baseRequest = new SmallPiecesOrderRequestDto();
            }

            if (mallOrderEntity.StartDate.HasValue)
            {
                baseRequest.IsBook = true;
                baseRequest.BookTime = mallOrderEntity.StartDate.Value;
            }

            baseRequest.UserId = 0;//XXXXX
            baseRequest.Shipping = sender.ContactName;
            if (!string.IsNullOrWhiteSpace(sender.Mobile))
                baseRequest.ShippingPhone = sender.Mobile;
            else
                baseRequest.ShippingPhone = sender.Tel;
            baseRequest.ShippingAddress = sender.Address;

            baseRequest.SourceType = OrderSourceType.Mall;
            baseRequest.FreightType = FreightType.General;

            baseRequest.GoodsAddress = GetGoodsAddress(goodsList.ToList(), sender, receiver);
            baseRequest.GoodsChecklist = GetGoodsCheckList(goodsList.ToList());

            baseRequest.VehicleTransportBusinessConfigId = 2;//XXXXXXXXX
            baseRequest.VehicleTransportBusinessType = transportBusinessType;

            baseRequest.CountyCode = sender.CountyCode;
            baseRequest.Longitude = sender.Lng;
            baseRequest.Latitude = sender.Lat;

            return baseRequest;
        }

        private List<OrderGoodsBaseRequestDto> GetGoodsAddress(List<MallOrderGoodsEntity> goodsList, MallOrderAddressEntity sender, MallOrderAddressEntity receiver)
        {
            List<OrderGoodsBaseRequestDto> list = new List<OrderGoodsBaseRequestDto>();
            bool senderExists = false;
            foreach (var item in goodsList)
            {
                var goods = new OrderGoodsBaseRequestDto();
                goods.GoodsName = item.GoodsName;
                goods.GoodsPhoto = item.GoodsPhoto;
                goods.GoodsWeight = item.GoodsWeight;
                goods.GoodsVolume = item.GoodsVolume;
                goods.GoodsLength = item.GoodsLength;
                goods.GoodsWidth = item.GoodsWidth;
                goods.GoodsHeight = item.GoodsHeight;
                goods.GoodsSku = item.GoodsSku;
                goods.GoodsUnit = item.GoodsUnit;
                goods.GoodsPrice = item.GoodsPrice;
                goods.GoodsCount = item.GoodsQuantity;
                goods.AddressType = senderExists ? AddressType.Take : AddressType.Place;

                goods.EndAddress = senderExists ? receiver.Address : sender.Address;
                goods.EndCountyCode = senderExists ? receiver.CountyCode : sender.CountyCode;
                goods.EndLongitude = senderExists ? receiver.Lng : sender.Lng;
                goods.EndLatitude = senderExists ? receiver.Lat : sender.Lat;
                goods.Consignee = senderExists ? receiver.ContactName : sender.ContactName;
                goods.ConsigneeGender = ContacterGenderType.Mr;
                if (!string.IsNullOrWhiteSpace(receiver.Mobile))
                    goods.ConsigneePhone = receiver.Mobile;
                else
                    goods.ConsigneePhone = receiver.Tel;
                goods.EndIndex = senderExists ? 1 : 0;
                list.Add(goods);

                senderExists = true;
            }
            return list;
        }

        private List<OrderGoodsChecklistRequestDto> GetGoodsCheckList(List<MallOrderGoodsEntity> goodsList)
        {
            var list = new List<OrderGoodsChecklistRequestDto>();
            foreach (var item in goodsList)
            {
                var goods = new OrderGoodsChecklistRequestDto();

                goods.GoodsName = item.GoodsName;
                goods.GoodsPhoto = item.GoodsPhoto;
                goods.GoodsWeight = item.GoodsWeight;
                goods.GoodsVolume = item.GoodsVolume;
                goods.GoodsLength = item.GoodsLength;
                goods.GoodsWidth = item.GoodsWidth;
                goods.GoodsHeight = item.GoodsHeight;
                goods.GoodsSku = item.GoodsSku;
                goods.GoodsUnit = item.GoodsUnit;
                goods.GoodsPrice = item.GoodsPrice;
                goods.GoodsCount = item.GoodsQuantity;
                list.Add(goods);
            }
            return list;
        }
        #endregion

        //获取跑腿车型ID
        private int GetRunErrandVehicleTypeId()
        {
            return 22;
        }

        #region 创建运输单
        private TransportOrderDto CreateTransportOrder(MallOrderEntity mallOrderEntity, MallOrderAddressEntity sender, MallOrderAddressEntity receiver)
        {
            TransportOrderRequestDto transportOrderRequestDto = new TransportOrderRequestDto();

            transportOrderRequestDto.TransportOrderNo = RandomCode.GetOrderNo("MallOrder", new SnowflakeWorker(int.Parse(configuration["Snowflake:DatacenterId"]), int.Parse(configuration["Snowflake:ServerId"])).NextId());
            transportOrderRequestDto.SourceType = OrderSourceType.Mall;
            transportOrderRequestDto.UserId = 0;

            if (mallOrderEntity.StartDate.HasValue)
            {
                transportOrderRequestDto.IsBook = true;
                transportOrderRequestDto.BookTime = mallOrderEntity.StartDate.Value;
            }
            else
            {
                transportOrderRequestDto.IsBook = false;
            }
            transportOrderRequestDto.IsSplitOrder = mallOrderEntity.IsNeedSplit;
            transportOrderRequestDto.TransportAmount = 0; //xxxx

            transportOrderRequestDto.CountyCode = sender.CountyCode;
            transportOrderRequestDto.Longitude = sender.Lng;
            transportOrderRequestDto.Latitude = sender.Lat;

            transportOrderRequestDto.EndCountyCode = receiver.CountyCode;
            transportOrderRequestDto.EndLongitude = receiver.Lng;
            transportOrderRequestDto.EndLatitude = receiver.Lat;

            var entity = transportOrderService.Add(transportOrderRequestDto);
            return entity;
        }
        #endregion
    }
}